package demo;

import javax.management.*;
import javax.management.openmbean.CompositeData;
import java.lang.management.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

public class JvmMemoryMonitor {
    
    /**
     * 获取完整的 JVM 内存指标
     */
    public static JvmMemoryMetrics getMemoryMetrics() {
        JvmMemoryMetrics metrics = new JvmMemoryMetrics();
        
        // 获取内存管理器
        MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
        
        // 获取堆内存信息
        MemoryUsage heapUsage = memoryMXBean.getHeapMemoryUsage();
        metrics.setHeapUsed(heapUsage.getUsed());
        metrics.setHeapCommitted(heapUsage.getCommitted());
        metrics.setHeapMax(heapUsage.getMax());
        
        // 获取非堆内存信息
        MemoryUsage nonHeapUsage = memoryMXBean.getNonHeapMemoryUsage();
        metrics.setMetaspaceUsed(nonHeapUsage.getUsed());
        metrics.setMetaspaceCommitted(nonHeapUsage.getCommitted());
        metrics.setMetaspaceMax(nonHeapUsage.getMax());
        
        // 获取直接内存信息
        metrics.setDirectMemoryUsed(getDirectMemoryUsage());
        
        // 获取内存池详情
        metrics.setMemoryPools(getMemoryPoolMetrics());
        
        // 获取 GC 统计信息
        metrics.setGcMetrics(getGcMetrics());
        
        // 获取 CPU 使用率
        metrics.setProcessCpuUsage(getProcessCpuUsage());
        metrics.setSystemCpuUsage(getSystemCpuUsage());
        
        return metrics;
    }
    
    /**
     * 获取直接内存使用情况
     */
    private static long getDirectMemoryUsage() {
        try {
            Class<?> clazz = Class.forName("java.nio.Bits");
            java.lang.reflect.Field maxMemoryField = clazz.getDeclaredField("maxMemory");
            java.lang.reflect.Field reservedMemoryField = clazz.getDeclaredField("reservedMemory");
            maxMemoryField.setAccessible(true);
            reservedMemoryField.setAccessible(true);
            
            Long maxMemory = (Long) maxMemoryField.get(null);
            AtomicLong reservedMemory = (AtomicLong) reservedMemoryField.get(null);
            
            return reservedMemory.get();
        } catch (Exception e) {
            // 如果无法通过反射获取，尝试通过 JMX
            try {
                MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
                ObjectName bufferPoolName = new ObjectName("java.nio:type=BufferPool,name=direct");
                AttributeList attributes = mBeanServer.getAttributes(bufferPoolName, new String[]{"MemoryUsed"});
                if (!attributes.isEmpty()) {
                    Attribute attribute = (Attribute) attributes.get(0);
                    return (Long) attribute.getValue();
                }
            } catch (Exception ex) {
                // 如果两种方式都失败，返回 -1
                return -1;
            }
            return -1;
        }
    }
    
    /**
     * 获取内存池详细信息
     */
    private static List<JvmMemoryMetrics.MemoryPoolMetrics> getMemoryPoolMetrics() {
        List<JvmMemoryMetrics.MemoryPoolMetrics> pools = new ArrayList<>();
        List<MemoryPoolMXBean> memoryPoolMXBeans = ManagementFactory.getMemoryPoolMXBeans();
        
        for (MemoryPoolMXBean pool : memoryPoolMXBeans) {
            JvmMemoryMetrics.MemoryPoolMetrics poolMetrics = new JvmMemoryMetrics.MemoryPoolMetrics();
            poolMetrics.setName(pool.getName());
            
            MemoryUsage usage = pool.getUsage();
            poolMetrics.setUsed(usage.getUsed());
            poolMetrics.setCommitted(usage.getCommitted());
            poolMetrics.setMax(usage.getMax());
            poolMetrics.setMemoryType(pool.getType().name());
            
            pools.add(poolMetrics);
        }
        
        return pools;
    }
    
    /**
     * 获取 GC 统计信息
     */
    private static List<JvmMemoryMetrics.GcMetrics> getGcMetrics() {
        List<JvmMemoryMetrics.GcMetrics> gcList = new ArrayList<>();
        List<GarbageCollectorMXBean> gcMXBeans = ManagementFactory.getGarbageCollectorMXBeans();
        
        for (GarbageCollectorMXBean gc : gcMXBeans) {
            JvmMemoryMetrics.GcMetrics gcMetrics = new JvmMemoryMetrics.GcMetrics();
            gcMetrics.setName(gc.getName());
            gcMetrics.setCount(gc.getCollectionCount());
            gcMetrics.setTime(gc.getCollectionTime());
            
            // 获取最后一次 GC 原因（需要尝试通过 JMX 获取）
            try {
                MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
                ObjectName gcName = new ObjectName("java.lang:type=GarbageCollector,name=" + gc.getName());
                CompositeData lastGcInfo = (CompositeData) mBeanServer.getAttribute(gcName, "LastGcInfo");
                if (lastGcInfo != null) {
                    String gcCause = (String) lastGcInfo.get("GcCause");
                    gcMetrics.setLastCause(gcCause);
                }
            } catch (Exception e) {
                gcMetrics.setLastCause("Unknown");
            }
            
            gcList.add(gcMetrics);
        }
        
        return gcList;
    }
    
    /**
     * 获取进程 CPU 使用率
     */
    private static double getProcessCpuUsage() {
        try {
            MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
            ObjectName osName = ObjectName.getInstance("java.lang:type=OperatingSystem");
            AttributeList attributes = mBeanServer.getAttributes(osName, new String[]{"ProcessCpuLoad"});
            
            if (!attributes.isEmpty()) {
                Attribute attribute = (Attribute) attributes.get(0);
                Double cpuUsage = (Double) attribute.getValue();
                return cpuUsage != null ? cpuUsage * 100 : 0; // 转换为百分比
            }
        } catch (Exception e) {
            // 处理异常
        }
        return 0;
    }
    
    /**
     * 获取系统 CPU 使用率
     */
    private static double getSystemCpuUsage() {
        try {
            MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
            ObjectName osName = ObjectName.getInstance("java.lang:type=OperatingSystem");
            AttributeList attributes = mBeanServer.getAttributes(osName, new String[]{"SystemCpuLoad"});
            
            if (!attributes.isEmpty()) {
                Attribute attribute = (Attribute) attributes.get(0);
                Double cpuUsage = (Double) attribute.getValue();
                return cpuUsage != null ? cpuUsage * 100 : 0; // 转换为百分比
            }
        } catch (Exception e) {
            // 处理异常
        }
        return 0;
    }
    
    /**
     * 打印内存指标信息（用于测试）
     */
    public static void printMemoryMetrics() {
        JvmMemoryMetrics metrics = getMemoryMetrics();
        
        System.out.println("=== JVM 内存监控指标 ===");
        System.out.printf("堆内存: Used=%d MB, Committed=%d MB, Max=%d MB%n",
                metrics.getHeapUsed() / 1024 / 1024,
                metrics.getHeapCommitted() / 1024 / 1024,
                metrics.getHeapMax() / 1024 / 1024);
        
        System.out.printf("元空间: Used=%d MB, Committed=%d MB, Max=%d MB%n",
                metrics.getMetaspaceUsed() / 1024 / 1024,
                metrics.getMetaspaceCommitted() / 1024 / 1024,
                metrics.getMetaspaceMax() / 1024 / 1024);
        
        System.out.printf("直接内存: Used=%d MB%n", metrics.getDirectMemoryUsed() / 1024 / 1024);
        
        System.out.println("\n=== 内存池详情 ===");
        for (JvmMemoryMetrics.MemoryPoolMetrics pool : metrics.getMemoryPools()) {
            System.out.printf("%s (%s): Used=%d MB, Committed=%d MB, Max=%d MB%n",
                    pool.getName(), pool.getMemoryType(),
                    pool.getUsed() / 1024 / 1024,
                    pool.getCommitted() / 1024 / 1024,
                    pool.getMax() / 1024 / 1024);
        }
        
        System.out.println("\n=== GC 统计 ===");
        for (JvmMemoryMetrics.GcMetrics gc : metrics.getGcMetrics()) {
            System.out.printf("%s: Count=%d, Time=%d ms, Last Cause=%s%n",
                    gc.getName(), gc.getCount(), gc.getTime(), gc.getLastCause());
        }
        
        System.out.printf("\n=== CPU 使用率 ===%n");
        System.out.printf("进程CPU: %.2f%%%n", metrics.getProcessCpuUsage());
        System.out.printf("系统CPU: %.2f%%%n", metrics.getSystemCpuUsage());
    }
    
    public static void main(String[] args) {
        // 测试代码
        printMemoryMetrics();
    }
}